/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.metadata.rtcustomization.servermanager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.inspur.edp.lcm.metadata.api.entity.*;
import com.inspur.edp.lcm.metadata.cache.*;
import com.inspur.edp.lcm.metadata.common.MetadataDtoConverter;
import com.inspur.edp.lcm.metadata.common.SerializerUtils;
import com.inspur.edp.lcm.metadata.common.ServiceFactory;
import com.inspur.edp.lcm.metadata.common.ServiceUtils;
import com.inspur.edp.lcm.metadata.common.context.RuntimeContext;
import com.inspur.edp.lcm.metadata.configuration.CustomizationCacheHelper;
import com.inspur.edp.metadata.rtcustomization.api.entity.MetadataFilter;
import com.inspur.edp.metadata.rtcustomization.api.entity.*;
import com.inspur.edp.metadata.rtcustomization.api.exception.ErrorCodes;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmMetadataException;
import com.inspur.edp.metadata.rtcustomization.api.exception.LcmParseException;
import com.inspur.edp.metadata.rtcustomization.common.EnvironmentContext;
import com.inspur.edp.metadata.rtcustomization.common.TenantUtils;
import com.inspur.edp.metadata.rtcustomization.common.configuration.MetadataBeforeSaveToDBHelper;
import com.inspur.edp.metadata.rtcustomization.common.configuration.MetadataSavedToDBHelper;
import com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationRtServerService;
import com.inspur.edp.metadata.rtcustomization.servermanager.dac.*;
import com.inspur.edp.metadata.rtcustomization.servermanager.repository.*;
import com.inspur.edp.metadata.rtcustomization.spi.EventSceneEnum;
import com.inspur.edp.metadata.rtcustomization.spi.MetadataBeforeSaveToDBExtend;
import com.inspur.edp.metadata.rtcustomization.spi.MetadataRtSpi;
import com.inspur.edp.metadata.rtcustomization.spi.MetadataSavedToDBExtend;
import com.inspur.edp.metadata.rtcustomization.spi.args.MetadataDeletedArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.MetadataDeletingArgs;
import com.inspur.edp.metadata.rtcustomization.spi.args.MetadataSavedArgs;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.i18n.entity.EcpLanguage;
import io.iec.edp.caf.i18n.api.LanguageService;
import io.iec.edp.caf.tenancy.api.ITenantService;
import io.iec.edp.caf.tenancy.api.entity.Tenant;
import io.iec.edp.caf.tenancy.core.context.MultiTenantContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhaoleitr
 */
@Slf4j
public class CustomizationRtServerServiceImpl extends AbstractMetadataService implements CustomizationRtServerService {
    private final ExtRelationRepoService extRelationRepoService;

    private final GspMdpkgRepoService gspMdpkgRepoService;

    private final CustomizationDataProducer cdp;

    private final MetadataRefsRepoService metadataRefsRepoService;

    private static final com.inspur.edp.lcm.metadata.configuration.CacheModeEnum cacheModeEnum = CustomizationCacheHelper.getInstance().getCacheMode();

    static {
        // 在启动过程中，注册bean的时候调用缓存清理方法，确保获取的元数据都是最新的。
        MetadataRtDistCache.getMetadataCache().clear();
        MetadataPackageOnDistCache.getMetadataPackageOnCache().clear();
    }

    public CustomizationRtServerServiceImpl(CustomizationMetadataRepository metadataRepository, CustomizationMetadataRefsRepository metadataRefsRepository,
                                            MetadataRtContentRepository mdRtContentRepo, CustomizationExtRelationRepo extRelationRepo,
                                            CustomizationDataProducer cdp, GspMdpkgRepository gspMdpkgRepo) {
        mdRtRepoService = new MdRtRepoService(mdRtContentRepo, gspMdpkgRepo,cdp);
        generatedRepoService = new GeneratedRepoService(metadataRepository, metadataRefsRepository, cdp);
        extRelationRepoService = new ExtRelationRepoService(extRelationRepo);
        gspMdpkgRepoService = new GspMdpkgRepoService(gspMdpkgRepo, mdRtRepoService);
        metadataRefsRepoService = new MetadataRefsRepoService(metadataRefsRepository);
        this.cdp = cdp;
    }

    @Override
    public List<Metadata4Ref> getAllCustomizedRtMetadataInfoWithTypes(String metadataTypes) {
        if (metadataTypes == null || metadataTypes.isEmpty()) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataTypes");
        }
        return mdRtRepoService.getAllCustomizedMetadata(metadataTypes);
    }

    @Override
    public List<DimensionExtendEntity> getExtMdByBasicMdId(String metadataId, String certId) {
        if (StringUtils.isEmpty(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        List<DimensionExtendEntity> result = new ArrayList<>();
        List<GspMdExtRelation> relations = extRelationRepoService.getExtRelationByBasicMdInfo(metadataId, certId);
        if (CollectionUtils.isEmpty(relations)) {
            return null;
        }
        relations.forEach(relation -> {
            GspMdRtContent customizedMetadata = mdRtRepoService.findByMetadataId(relation.getExtMdId());
            if (!Objects.isNull(customizedMetadata)) {
                result.add(buildDimensionExtendEntity(customizedMetadata, relation));
            }
        });
        return result;
    }

    @Override
    public void preloadMetadata(MetadataFilter metadataFilter) {
        // 获取元数据列表
        List<Metadata4Ref> metadataList = getMetadataListByFilter(metadataFilter);
        if (metadataList == null || metadataList.size() == 0) {
            return;
        }

        // 获取元数据，是否可并发？
        for (Metadata4Ref metadata : metadataList) {
            try {
                getMetadata(metadata.getMetadata().getHeader().getId());
            } catch (Exception e) {
                log.error("Failed to get metadata", e);
            }
        }
    }

    @Override
    public void saveMdpkg(File mdpkg, boolean isPatchAssembly) {
        // 解析获取元数据包String，各元数据String
        Map<String, String> fileContentMap = ServiceUtils.readCompressedFile(mdpkg);

        // 反序列化成GspMdRtContent和GspMdpkg，并存入数据库
        String manifestContent = fileContentMap.get(ServiceUtils.getManifestFileName());
        if (Objects.isNull(manifestContent)) {
            log.error("检测到元数据包中没有manifest.json信息, 此元数据包不入库, 元数据包为:{}", mdpkg.getAbsolutePath());
            throw new LcmParseException(ErrorCodes.ECP_PARSE_0007, mdpkg.getAbsolutePath());
        }
        MetadataPackage metadataPackage;
        try {
            metadataPackage = ServiceUtils.getMapper().readValue(manifestContent, MetadataPackage.class);
        } catch (JsonProcessingException e) {
            throw new LcmParseException(e, ErrorCodes.ECP_PARSE_0008, mdpkg.getAbsolutePath());

        }
        // 空元数据包时，不入库
        if (CollectionUtils.isEmpty(metadataPackage.getMetadataList())) {
            log.warn("元数据包中不存在元数据，不需要入库, 元数据包为:{}", mdpkg.getAbsolutePath());
            return;
        }

        // 删除需要删除的元数据
        boolean needSaveMetadata = deleteBDMetadata(isPatchAssembly, metadataPackage);
        if (!needSaveMetadata) {
            return;
        }

        GspMdpkg gspMdpkg = gspMdpkgRepoService.buildGspMdpkgByFileString(manifestContent, metadataPackage);
        List<GspMdRtContent> rtContentList = getGspMdRtContentList(fileContentMap, gspMdpkg);

        // 同步gspmdrefs表
        MetadataPackage mdPackage = SerializerUtils.deserialize(gspMdpkg.getManifestInfo(), MetadataPackage.class);
        List<GspMdRefs> gspMdRefs = metadataRefsRepoService.buildGspMdRefsByMetadataPackage(mdPackage);

        // 入库
        log.info(String.format("import %s", gspMdpkg.getName()));
        gspMdpkgRepoService.save(gspMdpkg);
        mdRtRepoService.saveAll(rtContentList);
        metadataRefsRepoService.saveAll(gspMdRefs);
        cdp.getEm().flush();
        cdp.getEm().clear();

        // 调用保存后的扩展功能
        invokeSavedExtend(gspMdpkg, rtContentList);
        // 元数据保存后事件，将扩展写法替换为bean写法，目前eapi在用
        invokeMetadataSavedSpi(gspMdpkg, rtContentList);
    }

    @Override
    public void saveMdpkgWithPreParse(File mdpkg, boolean isPatchAssembly, MetadataPackageParseResult preParseResult) {
        if (preParseResult == null || !preParseResult.isValid()) {
            log.warn("预解析结果无效，跳过保存");
            return;
        }

        // 删除需要删除的元数据
        boolean needSaveMetadata = deleteBDMetadata(isPatchAssembly, preParseResult.getMetadataPackage());
        if (!needSaveMetadata) {
            return;
        }

        GspMdpkg gspMdpkg = preParseResult.getGspMdpkg();
        // 同步gspmdrefs表
        MetadataPackage mdPackage = SerializerUtils.deserialize(gspMdpkg.getManifestInfo(), MetadataPackage.class);
        List<GspMdRefs> gspMdRefs = metadataRefsRepoService.buildGspMdRefsByMetadataPackage(mdPackage);
        List<GspMdRtContent> rtContentList = preParseResult.getRtContentList();

        // 入库
        log.info(String.format("import %s", gspMdpkg.getName()));
        gspMdpkgRepoService.save(gspMdpkg);
        mdRtRepoService.saveAll(rtContentList);
        metadataRefsRepoService.saveAll(gspMdRefs);
        cdp.getEm().flush();
        cdp.getEm().clear();

        // 调用保存后的扩展功能
        invokeSavedExtend(gspMdpkg, rtContentList);
        // 元数据保存后事件，将扩展写法替换为bean写法，目前eapi在用
        invokeMetadataSavedSpi(gspMdpkg, rtContentList);
    }

    @Override
    public MetadataPackageParseResult parseMetadataPackage(File mdpkg, MetadataPackage metadataPackage) {

            MetadataPackageParseResult result = new MetadataPackageParseResult();
            // 解析获取元数据包String，各元数据String
            Map<String, String> fileContentMap = ServiceUtils.readCompressedFile(mdpkg);
            result.setFileContentMap(fileContentMap);

            // 反序列化成GspMdRtContent和GspMdpkg，并存入数据库
            String manifestContent = fileContentMap.get(ServiceUtils.getManifestFileName());

            if (Objects.isNull(manifestContent)) {
                log.error("检测到元数据包中没有manifest.json信息, 此元数据包不入库, 元数据包为:{}", mdpkg.getAbsolutePath());
                throw new LcmParseException(ErrorCodes.ECP_PARSE_0007, mdpkg.getAbsolutePath());
            }
            if (metadataPackage != null) {
                result.setMetadataPackage(metadataPackage);
            } else {
                log.error("元数据包为空,元数据包为:{}", mdpkg.getAbsolutePath());
                return result;
            }
            // 空元数据包时，不入库
            if (CollectionUtils.isEmpty(metadataPackage.getMetadataList())) {
                log.warn("元数据包中不存在元数据，不需要入库, 元数据包为:{}", mdpkg.getAbsolutePath());
                return result;
            }

            // 构建GspMdRtContent列表
            GspMdpkg gspMdpkg = gspMdpkgRepoService.buildGspMdpkgByFileString(manifestContent, metadataPackage);
            result.setGspMdpkg(gspMdpkg);
            List<GspMdRtContent> rtContentList = getGspMdRtContentList(fileContentMap, gspMdpkg);
            result.setRtContentList(rtContentList);
            return result;
        }


    /**
     * 元数据保存后事件，将扩展写法替换为bean写法，目前eapi在用
     * @param gspMdpkg 元数据包信息，需使用里面的processMode信息
     * @param rtContentList 元数据列表
     */
    private void invokeMetadataSavedSpi(GspMdpkg gspMdpkg, List<GspMdRtContent> rtContentList) {
        EventSceneEnum eventScene = ServiceUtils.isDeployTool() ? EventSceneEnum.TOOL : EventSceneEnum.SERVER;
        for (GspMdRtContent gspMdRtContent : rtContentList) {
            MetadataRtSpi metadataRtService = ServiceFactory.getInstance().getMetadataRtService(gspMdRtContent.getType());
            // 保存后扩展适用于相同类型的元数据
            if (metadataRtService != null) {
                // 保存后扩展不适用于扩展的要过滤掉，如ExternalApi仅在发布时支持
                if (!metadataRtService.available(eventScene)) {
                    continue;
                }
                GspMetadata gspMetadata = mdRtRepoService.buildGspMetadataFromGspMdRtContent(gspMdRtContent);
                metadataRtService.metadataSaved(new MetadataSavedArgs(gspMetadata, ProcessMode.valueOf(gspMdpkg.getProcessmode())));
            }
        }
    }

    private void invokeSavedExtend(GspMdpkg gspMdpkg, List<GspMdRtContent> rtContentList) {
        rtContentList.forEach(gspMdRtContent -> {
            // 获取元数据 在 lcm_metadataextend 中是否配置了 Saved 作为save入数据库后扩展
            MetadataSavedToDBExtend manager = MetadataSavedToDBHelper.getInstance().getManager(gspMdRtContent.getType());
            // 若配置扩展则执行
            if (manager != null) {
                log.debug("CustomizationRtServerService.saveMdpkg mdkpgid[{}] - code [{}] has extend :[{}]",
                        gspMdRtContent.getMdpkgId(), gspMdRtContent.getCode(), manager.getClass());
                GspMetadata gspMetadata = mdRtRepoService.buildGspMetadataFromGspMdRtContent(gspMdRtContent);
                manager.execute(gspMetadata, ProcessMode.valueOf(gspMdpkg.getProcessmode()));
                log.debug("saveMdpkg extend finished");
            }
        });
    }

    private List<GspMdRtContent> getGspMdRtContentList(Map<String, String> fileContentMap, GspMdpkg gspMdpkg) {
        fileContentMap.remove(ServiceUtils.getManifestFileName());
        List<GspMdRtContent> rtContentList = new ArrayList<>();
        for (String key : fileContentMap.keySet()) {
            // 转为GspMdRtContent数据库实体
            GspMdRtContent gspMdRtContent = mdRtRepoService.buildGspMdRtContentFromFileString(fileContentMap.get(key), SourceTypeEnum.MDPKG, gspMdpkg.getId());
            if (Objects.isNull(gspMdRtContent)) {
                continue;
            }
            // 如果包中有两个相同metadataId的元数据，则只添加第一个元数据，不再添加第二个元数据
            if (rtContentList.stream().anyMatch(md -> md.getMetadataId().equals(gspMdRtContent.getMetadataId()))) {
                continue;
            }

            //如果存在元数据id比36位长，元数据舍弃
            if (gspMdRtContent.getMetadataId() != null && gspMdRtContent.getMetadataId().length() > 36) {
                continue;
            }
            rtContentList.add(gspMdRtContent);
        }

        rtContentList.forEach(gspMdRtContent -> {
            // 获取元数据 在 lcm_metadataextend 中是否配置了 BeforeSaveToDB 作为save入数据库前扩展
            MetadataBeforeSaveToDBExtend manager = MetadataBeforeSaveToDBHelper.getInstance().getManager(gspMdRtContent.getType());
            // 若配置扩展则执行
            if (manager != null) {
                log.debug("CustomizationRtServerService.saveMdpkg mdkpgid[{}] - code [{}] has extend :[{}]",
                        gspMdRtContent.getMdpkgId(), gspMdRtContent.getCode(), manager.getClass());
                GspMetadata gspMetadata = mdRtRepoService.buildGspMetadataFromGspMdRtContent(gspMdRtContent);
                String content = manager.execute(gspMetadata);
                if (!StringUtils.isEmpty(content)) {
                    gspMdRtContent.setContent(content);
                }
            }
        });
        return rtContentList;
    }

    /**
     * 删除数据库中的元数据
     */
    private boolean deleteBDMetadata(boolean isPatchAssembly, MetadataPackage metadataPackage) {
        GspMdpkg gspMdpkgDB = gspMdpkgRepoService.findByName(metadataPackage.getHeader().getName());
        if (Objects.nonNull(gspMdpkgDB)) {
            // 如果是补丁扩展入库，DB中存在元数据包则后续不在入库
            if (isPatchAssembly) {
                return false;
            }
            // 如果数据库中存在该元数据包信息，则获取需要删除的元数据
            List<GspMdRtContent> gspMdRtContentList = mdRtRepoService.findByMdpkgid(gspMdpkgDB.getId());
            if (!CollectionUtils.isEmpty(gspMdRtContentList)) {
                Map<String, GspMdRtContent> mdRtContentMap = gspMdRtContentList.stream().collect(Collectors.toMap(item -> item.getMetadataId(), item -> item));
                List<String> metadataIdsInDb = new ArrayList<>(mdRtContentMap.keySet());
                List<String> metadataIdsInMdpkg = new ArrayList<>();
                metadataPackage.getMetadataList().forEach(metadata -> metadataIdsInMdpkg.add(metadata.getHeader().getId()));
                metadataIdsInDb.removeAll(metadataIdsInMdpkg);
                if (!CollectionUtils.isEmpty(metadataIdsInDb)) {
                    metadataIdsInDb.forEach(metadataId -> {
                        GspMdRtContent currentMd = mdRtContentMap.get(metadataId);
                        MetadataHeader metadataHeader = new MetadataHeader(currentMd.getMetadataId(), currentMd.getNameSpace(), currentMd.getCode(), currentMd.getName(), currentMd.getType(), currentMd.getBizObjId());
                        // 元数据删除前事件
                        invokeMetadataDeletingSpi(new GspMetadata(metadataHeader));
                        mdRtRepoService.deleteMdRtContentByMetadataId(metadataId);
                        log.info("删除数据库中存在但元数据包中不存在的元数据 - MetadataID: {}, Code: {}, Type: {}",
                                metadataHeader.getId(),
                                metadataHeader.getCode(),
                                metadataHeader.getType());
                        // 删除mdrefs
                        metadataRefsRepoService.deleteByMdId(metadataId);
                        // 触发删除后事件
                        fireMetadataDeletedEvent(new GspMetadata(metadataHeader));
                        // 元数据删除后事件，将yaml写法替换为bean写法，目前eapi在用
                        invokeMetadataDeletedSpi(new GspMetadata(metadataHeader));
                    });
                }
            }
        }
        return true;
    }

    private void invokeMetadataDeletingSpi(GspMetadata gspMetadata) {
        MetadataRtSpi metadataRtService = ServiceFactory.getInstance().getMetadataRtService(gspMetadata.getHeader().getType());
        // 删除后扩展适用于相同类型的元数据
        if (metadataRtService != null) {
            // 删除后扩展不适用于扩展的要过滤掉
            EventSceneEnum eventScene = ServiceUtils.isDeployTool() ? EventSceneEnum.TOOL : EventSceneEnum.SERVER;
            if (!metadataRtService.available(eventScene)) {
                return;
            }
            metadataRtService.metadataDeleting(new MetadataDeletingArgs(gspMetadata));
        }
    }

    /**
     * 元数据删除后事件，将yaml写法替换为bean写法，目前eapi在用
     * @param gspMetadata 元数据，只有header
     */
    private void invokeMetadataDeletedSpi(GspMetadata gspMetadata) {
        MetadataRtSpi metadataRtService = ServiceFactory.getInstance().getMetadataRtService(gspMetadata.getHeader().getType());
        // 删除后扩展适用于相同类型的元数据
        if (metadataRtService != null) {
            // 删除后扩展不适用于扩展的要过滤掉
            EventSceneEnum eventScene = ServiceUtils.isDeployTool() ? EventSceneEnum.TOOL : EventSceneEnum.SERVER;
            if (!metadataRtService.available(eventScene)) {
                return;
            }
            metadataRtService.metadataDeleted(new MetadataDeletedArgs(gspMetadata));
        }
    }

    @Override
    public ServiceUnitInfo getServiceUnitInfo(String metadataId) {
        ServiceUnitInfo serviceUnitInfo = (ServiceUnitInfo) MetadataCacheManager.getServiceUnitInfo(metadataId);
        if (serviceUnitInfo != null) {
            return serviceUnitInfo;
        }

        Metadata4Ref metadata4Ref = mdRtRepoService.getPkgMetadataByMetadataId(metadataId);
        if (Objects.isNull(metadata4Ref)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0017,metadataId);
        }
        serviceUnitInfo = metadata4Ref.getServiceUnitInfo();

        MetadataCacheManager.putServiceUnitInfo(metadataId, serviceUnitInfo);

        return serviceUnitInfo;
    }

    @Override
    public Map<String, MetadataPackage> getMetadataPackagesRecursivly(String path) {
        return new MetadataPackageRepoService().getMetadataPackagesRecursivly(path);
    }

    @Override
    public List<GspMdpkg> findAllLastChangedOnFromMdpkg() {
        return gspMdpkgRepoService.findAllLastChangedOn();
    }

    @Override
    public MetadataPackage findMetadataPackageByName(String packageName) {
        MetadataPackage metadataPackage = MetadataPackageOnDistCache.get(packageName);
        if (metadataPackage != null) {
            return metadataPackage;
        }
        metadataPackage = gspMdpkgRepoService.findMetadataPackageByName(packageName);
        MetadataPackageOnDistCache.put(packageName, metadataPackage);
        return metadataPackage;
    }

    @Override
    public List<Metadata4Ref> getMetadataListByMdpkgName(String mdpkgName) {
        List<Metadata4Ref> metadataList = new ArrayList<>();
        GspMdpkg mdpkg = gspMdpkgRepoService.findByName(mdpkgName);
        if (mdpkg != null) {
            metadataList = mdRtRepoService.findAllByMdpkgid(mdpkg.getId());
        }
        return metadataList;
    }


    @Override
    public List<GspMdRtContent> getMdRtContentListByMdpkgName(String mdpkgName) {
        List<GspMdRtContent> mdRtContentList = new ArrayList<>();
        GspMdpkg mdpkg = gspMdpkgRepoService.findByName(mdpkgName);
        if (mdpkg != null) {
            mdRtContentList = mdRtRepoService.findAllGspMdRtContentsByMdpkgId(mdpkg.getId());
        }
        return mdRtContentList;
    }

    @Override
    public List<Metadata4Ref> getCustomizedList(MetadataFilter metadataFilter) {
        if (metadataFilter != null && metadataFilter.getSourceType() != null && metadataFilter.getSourceType() != SourceTypeEnum.CUSTOMIZED) {
            return null;
        }
        return mdRtRepoService.getAllCustomizedMetadata();
    }

    @Override
    public void initCache() {}

    @Override
    public void afterMdpkgChanged(boolean isFirst) {}

    @Override
    public void afterMdpkgChanged(MetadataPackage metadataPackage) {
        if (metadataPackage == null || CollectionUtils.isEmpty(metadataPackage.getMetadataList())) {
            return;
        }

        // 清除元数据缓存
        List<String> metadataIds = new ArrayList<>();
        metadataPackage.getMetadataList().forEach(metadata -> {
            metadataIds.add(metadata.getHeader().getId());
            MetadataCacheManager.putServiceUnitInfo(metadata.getHeader().getId(), metadataPackage.getServiceUnitInfo());
        });
        removeCacheByMetadataIds(metadataIds);

        // 清除元数据包缓存
        MetadataPackageOnDistCache.evict(metadataPackage.getHeader().getName());

        fireMdPkgChangedEvent(metadataPackage);

    }

    // 获取引用关系
    @Override
    public List<MetadataHeader> getMetadatasByRefedMetadataId(String metadataId) {
        return getMetadatasByRefedMetadataIdAndMetadataTypes(metadataId, null);
    }

    @Override
    public List<MetadataHeader> getMetadatasByRefedMetadataIdAndMetadataTypes(String metadataId, List<String> metadataTypes) {
        List<GspMdRefs> mdRefsByRefMdId = metadataRefsRepoService.getMdRefsByRefMdId(metadataId);
        List<MetadataHeader> metadataHeaders = new ArrayList<>();
        mdRefsByRefMdId.forEach(gspMdRefs -> {
            // metadataTypes为null的时候全部都要，不为null的时候根据类型过滤
            if (metadataTypes == null || metadataTypes.contains(gspMdRefs.getMdType())) {
                metadataHeaders.add(new MetadataHeader(gspMdRefs.getMdId(), gspMdRefs.getMdNameSpace(), gspMdRefs.getMdCode(), null, gspMdRefs.getMdType(), null));
            }
        });
        return metadataHeaders;
    }

    @Override
    public void initMdRefs() {
        if (metadataRefsRepoService.isInitilized()) {
            return;
        }

        // 4w元数据10分钟，异常了继续
        metadataRefsRepoService.setInitilizedStatus(InitilizedStatusEnum.INITIALIZING);
        List<GspMdpkg> allManifest = gspMdpkgRepoService.findAllManifest();
        if (!CollectionUtils.isEmpty(allManifest)) {
            allManifest.stream().parallel().forEach(gspMdpkg -> {
                try {
                    if (gspMdpkg != null && gspMdpkg.getManifestInfo() != null) {
                        MetadataPackage metadataPackage = SerializerUtils.deserialize(gspMdpkg.getManifestInfo(), MetadataPackage.class);
                        if (metadataPackage != null) {
                            List<GspMdRefs> gspMdRefs = metadataRefsRepoService.buildGspMdRefsByMetadataPackage(metadataPackage);
                            metadataRefsRepoService.saveAll(gspMdRefs);
                        }
                    }
                } catch (Exception e) {
                    log.info("无法更新元数据引用：[{}]", gspMdpkg.getName(), e);
                }
            });
        }

        metadataRefsRepoService.setInitilizedStatus(InitilizedStatusEnum.INITIALIZED);
    }

    @Override
    public void makeUnique() {
        gspMdpkgRepoService.makeUnique();
        mdRtRepoService.makeUnique();
    }

    private DimensionExtendEntity buildDimensionExtendEntity(GspMdRtContent mdContent, GspMdExtRelation relation) {
        DimensionExtendEntity extendEntity = new DimensionExtendEntity();
        extendEntity.setFirstDimension(relation.getFirstDimValue());
        extendEntity.setSecondDimension(relation.getSecDimValue());
        extendEntity.setBasicMetadataId(relation.getBasicMdId());
        extendEntity.setBasicMetadataCertId(relation.getBasicMdCertId());
        extendEntity.setBasicMetadataCode(relation.getBasicMdCode());
        extendEntity.setBasicMetadataNamespace(relation.getBasicMdNameSpace());
        extendEntity.setBasicMetadataVersion(relation.getBasicMdVersion());
        extendEntity.setBasicMetadataTypeStr(relation.getBasicMdType());
        extendEntity.setFirstDimensionName(relation.getFirstDimName());
        extendEntity.setFirstDimensionCode(relation.getFirstDimCode());
        extendEntity.setSecondDimensionName(relation.getSecDimName());
        extendEntity.setSecondDimensionCode(relation.getSecDimCode());
        GspMetadata metadata = mdRtRepoService.buildGspMetadataWithoutContentFromGspMdRtContent(mdContent);
        extendEntity.setExtendMetadataEntity(metadata);
        return extendEntity;
    }

    @Override
    public void preloadAllGeneratedMetadata() {
        if (cacheModeEnum == com.inspur.edp.lcm.metadata.configuration.CacheModeEnum.MULTI_TENANT) {
            multiTenantPreload();
        } else {
            singleTenantPreload();
        }
    }

    public void multiTenantPreload() {
        ITenantService tenantService = SpringBeanUtils.getBean(ITenantService.class);
        List<Tenant> allTenants = tenantService.getAllTenants(CAFContext.current.getLanguage());
        if (CollectionUtils.isEmpty(allTenants)) {
            return;
        }

        for (Tenant tenant : allTenants) {
            // 在context中设置租户信息
            MultiTenantContextHolder.set(TenantUtils.buildTenantContext(tenant));
            singleTenantPreload();
        }
    }

    private void singleTenantPreload() {
        LanguageService languageService = SpringBeanUtils.getBean(LanguageService.class);
        List<EcpLanguage> languages = languageService.getAllLanguages();
        List<Metadata4Ref> metadataList = generatedRepoService.getAllRTGeneratedMetadata();
        if (!CollectionUtils.isEmpty(metadataList)) {
            for (Metadata4Ref metadata4Ref : metadataList) {
                try {
                    GspMetadata metadata = generatedRepoService.getMetadata(metadata4Ref.getMetadata().getHeader().getId());
                    for (EcpLanguage language : languages) {
                        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadata.getHeader().getId(), language.getCode());
                        MetadataRtDistCache.put(metadataKey, metadata, MetadataRtDistCache.SECOND_CACHE);
                    }
                } catch (Exception e) {
                    log.error("预加载元数据异常", e);
                }
            }
        }
    }

    @Override
    public void saveSuInfoToCache() {
        List<GspMdRtContentSuInfo> allGspMdRtContentSuInfo = mdRtRepoService.findAllGspMdRtContentSuInfo();
        if (CollectionUtils.isEmpty(allGspMdRtContentSuInfo)) {
            return;
        }
        allGspMdRtContentSuInfo.forEach(su -> {
            MetadataCacheManager.putServiceUnitInfo(su.getMetadataId(), new ServiceUnitInfo(su.getAppcode(), su.getServiceunitcode()));
        });
    }

    @Override
    public void updateMetadata(GspMetadata metadata) {
        if (metadata == null) {
            return;
        }

        // 获取元数据的processMode
        ProcessMode processMode = getProcessModeByMetadataId(metadata.getHeader().getId());

        // 更新前元数据事件
        fireMetadataSavingEvent(metadata, processMode);

        // 元数据更新
        mdRtRepoService.updateMetadata(metadata);

        // 清除缓存
        removeCacheByMetadataIds(Collections.singletonList(metadata.getHeader().getId()));

        // 更新后事件
        fireMetadataSavedEvent(metadata, processMode);
    }

    @Override
    protected GspMetadata getMetadataFromDb(String metadataId) {
        //1、从运行时表中获取，获取包中的元数据、获取运行时定制发布的元数据
        GspMetadata metadata = mdRtRepoService.getRtMetadata(metadataId);
        if (metadata != null) {
            return metadata;
        }
        //2、从运行时生成的表中获取
        metadata = generatedRepoService.getMetadata(metadataId);
        return metadata;
    }

    @Override
    protected GspMetadata getMetadataFromCache(String metadataId, boolean isI18n) {
        // 如果缓存模式是调试模式，则不用缓存
        if (EnvironmentContext.cacheMode == CacheModeEnum.debug) {
            return null;
        }
        return MetadataRtDistCache.get(metadataId, isI18n);
    }

    @Override
    protected void putMetadataToCache(String metadataId, GspMetadata metadata, boolean isI18n) {
        String language = isI18n ? RuntimeContext.getLanguage() : "";
        String metadataKey = RtCacheHandler.getMetadataCacheKey(metadataId, language);
        MetadataRtDistCache.put(metadataKey, metadata, MetadataRtDistCache.SECOND_CACHE);
    }

    @Override
    protected MetadataStringDto getCustomizedMetadataStringDto(String metadataId) {
        GspMdRtContent gspMdRtContent = mdRtRepoService.findByMetadataIdAndSourceType(metadataId, SourceTypeEnum.CUSTOMIZED);
        if (gspMdRtContent != null) {
            return new MetadataStringDto(gspMdRtContent.getContent(), gspMdRtContent.getLastChangedOn().toString());
        } else {
            return null;
        }
    }

    @Override
    public GspMetadata getCustomizedMetadata(String metadataId) {
        return mdRtRepoService.getRtMetadataByMetadataIdAndSourceType(metadataId, SourceTypeEnum.CUSTOMIZED);
    }

    @Override
    public MetadataDto getCustomizedMetadataDto(String metadataId) {
        GspMetadata metadata = mdRtRepoService.getRtMetadataByMetadataIdAndSourceType(metadataId, SourceTypeEnum.CUSTOMIZED);
        return MetadataDtoConverter.asDto(metadata);
    }

    @Override
    public Metadata4Ref getMetadata4Ref(String metadataId) {
        Metadata4Ref metadata4Ref = mdRtRepoService.getMetadata4RefByMetadataId(metadataId);
        if (metadata4Ref == null) {
            return null;
        }
        // 对元数据进行国际化处理
        getI18nMetadata(metadata4Ref.getMetadata(), RuntimeContext.getLanguage());
        return metadata4Ref;
    }

    @Override
    public Metadata4RefDto getMetadata4RefDto(String metadataId) {
        Metadata4Ref metadata4Ref = getMetadata4Ref(metadataId);
        Metadata4RefDto dto = new Metadata4RefDto();
        MetadataDto metadataDto = MetadataDtoConverter.asDto(metadata4Ref.getMetadata());
        dto.setPackageHeader(metadata4Ref.getPackageHeader());
        dto.setMetadata(metadataDto);
        dto.setServiceUnitInfo(metadata4Ref.getServiceUnitInfo());
        return dto;
    }

    @Override
    public Metadata4Ref getMetadata4RefWithSourceType(String metadataId) {
        if (!StringUtils.hasLength(metadataId)) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "metadataId");
        }
        Metadata4Ref metadata4Ref = mdRtRepoService.getMetadata4RefWithResourceType(metadataId);
        if (metadata4Ref == null) {
            metadata4Ref = generatedRepoService.getRTGeneratedMetadataById(metadataId, true);
            if (metadata4Ref != null) {
                metadata4Ref.setSourceType(SourceTypeEnum.GENERATED);
            }
        }
        return metadata4Ref;
    }

    @Override
    public Metadata4Ref getMetadata4RefById(String metadataId){
        Metadata4Ref metadata4Ref = generatedRepoService.getRTGeneratedMetadataById(metadataId, true);
        if(metadata4Ref == null) {
            metadata4Ref = mdRtRepoService.getMetadata4RefById(metadataId);
        }
        return metadata4Ref;
    }

    @Override
    public ChangeMetadataSourceTypeResponse changeMetadataSourceType(List<ChangeMetadataSourceTypeInfo> changeInfos) {
        // 参数预校验
        if (changeInfos == null || changeInfos.isEmpty()) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "changeInfos");
        }
        changeInfos.forEach(this::validateChangeInfo);

        return mdRtRepoService.changeMetadataSourceType(changeInfos);
    }

    private void validateChangeInfo(ChangeMetadataSourceTypeInfo changeInfos) {
        if (!StringUtils.hasLength(changeInfos.getMdpkgName())) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "mdpkgName");
        }
        SourceTypeEnum sourceType = changeInfos.getSourceType();
        if (sourceType == null) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0003, "sourceType");
        }
        if (sourceType.getCode() != 0 && sourceType.getCode() != 2) {
            throw new LcmMetadataException(ErrorCodes.ECP_METADATA_0022, sourceType.toString());
        }
    }
}
